﻿using System.Collections.Generic;
using System.Linq;
using Entities;
using System.Data.Objects;
using System.Reflection;
using System.Linq.Expressions;
using System;

namespace Services
{
    public abstract class BaseReportingService
    {
        protected IQueryable<AuditedOperation> FilterOperations(FilterOperations filter, IQueryable<AuditedOperation> operations)
        {
            if (filter.StartDate.HasValue)
            {
                operations = operations.Where(o => o.ReceivedTime.HasValue && EntityFunctions.TruncateTime(o.ReceivedTime) >= EntityFunctions.TruncateTime(filter.StartDate.Value));
            }
            if (filter.EndDate.HasValue)
            {
                operations = operations.Where(o => o.ReceivedTime.HasValue && EntityFunctions.TruncateTime(o.ReceivedTime) <= EntityFunctions.TruncateTime(filter.EndDate.Value));
            }
            if (filter.RenderFileType && filter.FileTypes.Any())
            {
                operations = operations.Where(o => filter.FileTypes.Contains(o.FileType));
            }
            if (filter.RenderFileName && !string.IsNullOrEmpty(filter.FileName))
            {
                operations = operations.Where(o => o.ObjectName.Contains(filter.FileName));
            }
            if (!string.IsNullOrEmpty(filter.User))
            {
                operations = operations.Where(o => o.UserAccount.Contains(filter.User));
            }
            if (filter.Hosts.Any())
            {
                operations = operations.Where(o => filter.Hosts.Contains(o.ServerName));
            }
            if (filter.Policies.Any())
            {
                operations = operations.Where(o => filter.Policies.Contains(o.PolicyName));
            }
            if (filter.OperationTypes.Any())
            {
                operations = operations.Where(o => filter.OperationTypes.Contains((int)o.OperationType));
            }

            return operations;
        }

        protected IEnumerable<AuditedOperation> PageRecords(IQueryable<AuditedOperation> records, int page, out int totalCount, string columnName, bool isDescending, int pageSize)
        {
            totalCount = records.Count();

            var tType = typeof(AuditedOperation);
            PropertyInfo prop = tType.GetProperty(columnName);

            var funcType = typeof(Func<,>)
                    .MakeGenericType(tType, prop.PropertyType);

            var lambdaBuilder = typeof(Expression)
                .GetMethods()
                .First(x => x.Name == "Lambda" && x.ContainsGenericParameters && x.GetParameters().Length == 2)
                .MakeGenericMethod(funcType);

            var parameter = Expression.Parameter(tType);
            var propExpress = Expression.Property(parameter, prop);

            var sortLambda = lambdaBuilder
                .Invoke(null, new object[] { propExpress, new ParameterExpression[] { parameter } });

            var sorter = typeof(Queryable)
                .GetMethods()
                .FirstOrDefault(x => x.Name == (isDescending ? "OrderByDescending" : "OrderBy") && x.GetParameters().Length == 2)
                .MakeGenericMethod(new[] { tType, prop.PropertyType });

            records = (IQueryable<AuditedOperation>)sorter.Invoke(null, new object[] { records, sortLambda });
            return records.Skip((page - 1) * pageSize).Take(pageSize);
        }
    }
}